#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <cstdlib>
#include <new>
#include <typeinfo>
#include <list>
#include <thread> // std::thread
#include <mutex>  // std::mutex

using namespace std;

// 参考: https://blog.csdn.net/misayaaaaa/article/details/53786215
// 参考: https://github.com/applenob/Cpp_Primer_Practice
// chapter 7



// 10.
在下面这条if语句中，条件部分的作用是什么？

if (read(read(cin, data1), data2)) //等价read(std::cin, data1);read(std::cin, data2);
解：

read函数的返回值是istream对象， if语句中条件部分的作用是从输入流中读取数据给两个data对象



// 16.
在类的定义中对于访问说明符出现的位置和次数有限定吗？ 如果有，是什么？什么样的成员应该定义在public说明符之后？ 什么样的成员应该定义在private说明符之后？

如果某个成员能够在整个程序内都被访问，那么它应该定义为public; 如果某个成员只能在类内部访问，那么它应该定义为private

// 20.

友元在什么时候有用？请分别举出使用友元的利弊。

解：

当其他类或者函数想要访问当前类的私有变量时，这个时候应该用友元。

利：

与当前类有关的接口函数能直接访问类的私有变量。

弊：

牺牲了封装性与可维护性。





// 25.
Screen能安全地依赖于拷贝和赋值操作的默认版本吗？ 如果能，为什么？如果不能？为什么？

解：

能。 Screen的成员只有内置类型和string，因此能安全地依赖于拷贝和赋值操作的默认版本。

管理动态内存的类则不能依赖于拷贝和赋值操作的默认版本，而且也应该尽量使用string和vector来避免动态管理内存的复杂性。




// 30.

通过this指针使用成员的做法虽然合法，但是有点多余。讨论显示使用指针访问成员的优缺点。

解：

优点：

程序的意图更明确

函数的参数可以与成员同名，如

  void setAddr(const std::string &addr) { this->addr = addr; }
缺点：

有时候显得有点多余，如

std::string getAddr() const { return this->addr; }




//  46.
下面哪些论断是不正确的？为什么？

(a) 一个类必须至少提供一个构造函数。
(b) 默认构造函数是参数列表为空的构造函数。
(c) 如果对于类来说不存在有意义的默认值，则类不应该提供默认构造函数。
(d) 如果类没有定义默认构造函数，则编译器将为其生成一个并把每个数据成员初始化成相应类型的默认值。
解：

(a) 不正确。如果我们的类没有显式地定义构造函数，那么编译器就会为我们隐式地定义一个默认构造函数，并称之为合成的默认构造函数。
(b) 不完全正确。为每个参数都提供了默认值的构造函数也是默认构造函数。
(c) 不正确。哪怕没有意义的值也需要初始化。
(d) 不正确。只有当一个类没有定义任何构造函数的时候，编译器才会生成一个默认构造函数。
练习7.47

（a）：错误，类本身不提供构造函数时，编译器会自动合成一个默认构造函数
（b）：错误，为成员提供默认值的构造函数也成为默认构造函数
（c）：错误，见43题知识点1
（d）：错误，当类没有定义构造函数时，才会默认编译器生成默认构造函数。



// 47.

说明接受一个string参数的Sales_data构造函数是否应该是explicit的，并解释这样做的优缺点。

解：

是否需要从string到Sales_data的转换依赖于我们对用户使用该转换的看法。在此例中，这种转换可能是对的。null_book中的string可能表示了一个不存在的ISBN编号。

优点：

可以抑制构造函数定义的隐式转换

缺点：

为了转换要显式地使用构造函数



// 51.
vector将其单参数的构造函数定义成explicit的，而string则不是，你觉得原因何在？

假如我们有一个这样的函数：

int getSize(const std::vector<int>&);
如果vector没有将单参数构造函数定义成explicit的，我们就可以这样调用：

getSize(34);
很明显这样调用会让人困惑，函数实际上会初始化一个拥有34个元素的vector的临时量，然后返回34。但是这样没有任何意义。而string则不同，string的单参数构造函数的参数是const char *，因此凡是在需要用到string的地方都可以用 const char *来代替（字面值就是const char *）。如：

void print(std::string);
print("hello world");





// 56. 什么是类的静态成员？它有何优点？静态成员与普通成员有何区别？
56：知识点1：类的静态成员：该成员只需与类的本身有关，而不是与类的对象有关，加上static关键字即可声明，其不与任何实例化对象绑定，但是我们仍然可以使用类作用域运算符访问静态成员。
知识点2：static声明在内部。在外部定义时，不加static.类似与一个全局变量，其初始值必须是常量表达式。
知识点3：静态成员独立于任何对象，其类型可以是它所属的类类型。而非静态成员只能声明为其类的指针或引用









// 58.
下面的静态数据成员的声明和定义有错误吗？请解释原因。

//example.h
class Example {
public:
	static double rate = 6.5;
	static const int vecSize = 20;
	static vector<double> vec(vecSize);
};

//example.c
#include "example.h"
double Example::rate;
vector<double> Example::vec;
解：

rate应该是一个常量表达式。而类内只能初始化整型类型的静态常量，所以不能在类内初始化vec。修改后如下：

// example.h
class Example {
public:
    static constexpr double rate = 6.5;
    static const int vecSize = 20;
    static vector<double> vec;
};

// example.C
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);










int main()
{
   
    printf("hello c++ \n");
}